<template>
    <div ref="containerRef" class="editor-container"></div>
</template>

<script setup lang="ts">
import { ref, watch, onMounted, onBeforeUnmount, defineProps, nextTick } from 'vue'
import { useDebounceEffect } from '../../hooks/useDebounceEffect';
import * as monaco from 'monaco-editor'

const props = defineProps<{
  original: string
  modified: string
  language?: 'typescript' | 'javascript' | 'json'
}>()

const containerRef = ref<HTMLDivElement | null>(null)
let diffEditor: monaco.editor.IStandaloneDiffEditor | null = null
const originalContent = ref("");
const currentLanguage = ref(props.language ?? 'json')

const options = ref<monaco.editor.IDiffEditorConstructionOptions>({
    diffCodeLens: true,
    automaticLayout: true,
    readOnly: false, // 是否只读
    lineNumbers: 'on',
    ignoreTrimWhitespace: false,
    renderSideBySide: true,
    originalEditable: true, // 原始数据是否可编辑
    roundedSelection: false, // 右侧不显示编辑器预览框
})

let originalModel: monaco.editor.ITextModel
let modifiedModel: monaco.editor.ITextModel

onMounted(() => {

  originalContent.value = props.original;
  originalModel = monaco.editor.createModel(props.original, currentLanguage.value, )
  modifiedModel = monaco.editor.createModel(props.modified, currentLanguage.value)

  diffEditor = monaco.editor.createDiffEditor(containerRef.value!, options.value)
  diffEditor.setModel({
    original: originalModel,
    modified: modifiedModel,
  })
  // 当原始模型内容改变时，重新检测语言并应用到原始和修改模型
  originalModel.onDidChangeContent(() => {
    originalContent.value = originalModel.getValue();
  });
    // 需要等待 DOM 更新
  nextTick(async () => {

      // 添加 50ms 延迟确保窗口完全渲染
      setTimeout(() => {
          containerRef.value?.focus()
      }, 50)
  })

})
onBeforeUnmount(() => {
  originalModel?.dispose()
  modifiedModel?.dispose()
  diffEditor?.dispose()
})

watch(() => props.original, (val) => {
  if (originalModel && val !== originalModel.getValue()) {
    originalModel.setValue(val)
  }
})
watch(() => props.modified, (val) => {
  if (modifiedModel && val !== modifiedModel.getValue()) {
    modifiedModel.setValue(val)
  }
})
watch(currentLanguage, (lang) => {
  if (originalModel) monaco.editor.setModelLanguage(originalModel, lang)
  if (modifiedModel) monaco.editor.setModelLanguage(modifiedModel, lang)
})
watch(() => props.language, (lang) => {
  if (lang && lang !== currentLanguage.value) {
    currentLanguage.value = lang
  }
})

// 把 invoke 的逻辑放到这里
useDebounceEffect(originalContent, (val) => {

  const langId = detectByContent(val); // 自定义内容检测函数，返回语言 ID
  console.log("----" + langId)
  monaco.editor.setModelLanguage(originalModel, langId);
  monaco.editor.setModelLanguage(modifiedModel, langId);
}, 800)  // 800 ms 防抖

function detectByContent(code: string): string {
  const t = code.trim();
  // HTML 优先，常用 html 标签
  if (/^<(!doctype|html|head|body|div|span|script|style|[a-z]+\s)/i.test(t))
    return 'html';
  // XML，要求有 <?xml 或自定义标签，并且排除 html 关键词
  if (
    /^<\?xml\s/.test(t) ||
    (/^<([a-zA-Z0-9]+)(\s|>)/.test(t) &&
      !/^<(html|head|body|div|span|script|style)/i.test(t))
  ) {
    return 'xml';
  }
  // JSON
  if (/^(?:\{[\s\S]*\}|\[[\s\S]*\])$/.test(t))
    return 'json';
  // YAML，且排除 < 开头
  if (!t.startsWith("<") && (/^---/.test(t) || /^[\w\-]+\s*:\s*.+/m.test(t))) {
    return 'yaml';
  }
  // Markdown
  if (/^#+\s+/m.test(t) || /\[[^\]]+\]\([^)]+\)/.test(t))
    return 'markdown';
  // SQL
  if (
    /\b(SELECT|INSERT|UPDATE|DELETE|CREATE|DROP|ALTER|TRUNCATE|FROM|WHERE|JOIN)\b/i.test(t)
  ) {
    return 'sql';
  }
  // JavaScript
  if (/;\s*$/.test(t) || /\bfunction\b/.test(t))
    return 'javascript';
  // TypeScript
  if (/\:\s*string\b/.test(t) || /\binterface\b/.test(t))
    return 'typescript';
  // CSS
  if (/^[\w-]+\s*\{[\s\S]*\}/.test(t))
    return 'css';
  // fallback
  return 'javascript';
}
</script>

<style scoped>
.diff-editor-wrapper {
  display: flex;
  flex-direction: column;
  width: 100%;
  min-width: 600px;
}

.controls {
  margin-bottom: 10px;
}

.editor-container {
  flex-grow: 1;
  height: calc(100vh);
  width: 100%;
  border: 1px solid #ccc;
  box-sizing: border-box;
}
</style>
